package com.kayak.easysp.transbase;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Map;

import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.MDC;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.alibaba.dubbo.rpc.RpcException;
import com.kayak.dbutil.sql.SqlException;
import com.kayak.dubbo.bean.ConsumerBean;
import com.kayak.dubbo.bean.RpcBean;
import com.kayak.dubbo.global.RpcGlobal;
import com.kayak.easysp.appsecurity.APPEncrypt;
import com.kayak.easysp.util.ConsumerBeanUtil;
import com.kayak.easysp.util.ErrorCodeEasysp;
import com.kayak.easysp.util.OutErrorCodeEasysp;
import com.kayak.easysp.util.TransConstEasysp;
import com.kayak.easysp.util.TransUtilEasysp;
import com.kayak.exception.ErrorException;
import com.kayak.kkutils.CalendarUtil;
import com.kayak.kkutils.JsonUtil;
import com.kayak.kkutils.idGenerator.IdGenerator;
import com.kayak.kkutils.security.KKAES;
import com.kayak.kkutils.strutil.StringUtil;
import com.kayak.kkweb.sys.Global;
import com.kayak.kkweb.sys.SysBeans;
import com.kayak.service.security.acctlevel.QryAcctSecurityStepInterface;
import com.kayak.service.security.secretkey.GetMainKeyInterface;
import com.kayak.service.security.secretkey.GetWorkKeyInterface;
import com.kayak.service.user.custinfo.GetCustInfoInterface;
import com.kayak.service.user.entUser.GetEntUserInfoInterface;
import com.kayak.service.user.statistics.AddHomeVisitInterface;
import com.kayak.service.user.statistics.AddPayTimesDayInterface;
import com.kayak.service.user.statistics.ModUserFlagInterface;

/**
 * 所有交易父类
 * @date 2016年8月11日 10:56:35
 * */
public abstract class TransBase {

	public static final Logger log = LoggerFactory.getLogger(TransBase.class);
	@Autowired
	private GetMainKeyInterface getMainKeyService;//获得主密钥服务
	@Autowired
	private GetWorkKeyInterface getWorkKeyService;//活的工作密钥服务
	@Autowired
	protected GetCustInfoInterface getCustInfoService;//获取用户信息(用户是否登录)
	@Autowired
	protected QryAcctSecurityStepInterface qryAcctSecurityStepService;//获取用户安全状态
	@Autowired
	private AddHomeVisitInterface addHomeVisitService;//记录首页记录
	@Autowired
	private AddPayTimesDayInterface addPayTimesDayService;//添加付费次数记录
	@Autowired
	private ModUserFlagInterface modUserFlagService;//添加用户表示
	
	@Autowired
	private GetEntUserInfoInterface getEntUserInfoService;//获取企业用户信息(企业用户是否登录)
	
	protected static IdGenerator idg=new IdGenerator();
	
	/**
	 * 入口方法 根据transCode获取交易实例并执行
	 * add by guancj 20160304 
	 * Action调用的方法入口
	 * 
	 * @param transCode
	 *            交易码
	 * @param params
	 *            参数
	 * @param response
	 *            返回
	 */

	public static void doService(String transCode, Map<String, Object> params, HttpServletResponse response) {
		params.put(RpcGlobal.TRANS_ID, idg.nextId());
		MDC.put(RpcGlobal.TRANS_ID, params.get(RpcGlobal.TRANS_ID));
		log.info("TRANS_ID-["+params.get(RpcGlobal.TRANS_ID)+"]");
		TransBean transBean = new TransBean();
		if (params == null || params.size() == 0 || StringUtil.isEmpty(transCode)) {
			transBean.addLocalParam("ret_msg", "服务已启动！");
			transBean.addLocalParam("ret_code", "ok");
			returnClient((ServletResponse) response, transBean);
			return;
		}
		transBean.setRequest((Map<String, Object>) params);
		transBean.getLocalMap().putAll(params);
		try {
			if (StringUtils.isBlank(transCode)) {
				throw new ErrorException(ErrorCodeEasysp.ERROR_EASYSP_F901_CODE,ErrorCodeEasysp.ERROR_EASYSP_F901_MSG );
			}
			transBean.addLocalParam("trans_code", transCode);
			// 根据交易码生成实例
			TransBase comnService = (TransBase) SysBeans.getBean("t" + transCode);
			if (comnService == null) {
				throw new ErrorException("系统异常");
			}
			comnService.doMain(transBean);
			if(transBean.getLocal("ret_code")==null || transBean.getLocal("ret_code").equals("")){
				transBean.addLocalParam(ErrorCodeEasysp.RET_CODE, ErrorCodeEasysp.RET_SUC_CODE);
				transBean.addLocalParam(ErrorCodeEasysp.RET_MSG, ErrorCodeEasysp.RET_SUC_MSG);
			}
		} catch (ErrorException e) {
			e.printStackTrace();
			log.error(e.getMessage(), e);
			if (e.getErroCode() == null) {
				// 通用返回错误
				transBean.addLocalParam(ErrorCodeEasysp.RET_CODE,  TransConstEasysp.retCodeFail);
				transBean.addLocalParam(ErrorCodeEasysp.RET_MSG, TransConstEasysp.retMsgFail);
			} else {
				transBean.addLocalParam(ErrorCodeEasysp.RET_CODE, e.getErroCode());
				transBean.addLocalParam(ErrorCodeEasysp.RET_MSG, e.getMessage());
			}
		} catch (Exception e) {
			e.printStackTrace();
			log.error(e.getMessage(), e);
			transBean.addLocalParam(ErrorCodeEasysp.RET_CODE, TransConstEasysp.retCodeFail);
			transBean.addLocalParam(ErrorCodeEasysp.RET_MSG, TransConstEasysp.retMsgFail);
		} finally {
			try{
				String retmsg = OutErrorCodeEasysp.getRetmsg(transBean.getLocal(ErrorCodeEasysp.RET_CODE));
				transBean.addLocalParam(ErrorCodeEasysp.RET_MSG, 
						StringUtil.isNotEmpty(retmsg) ? retmsg : transBean.getLocal(ErrorCodeEasysp.RET_MSG));
			}catch(Exception e){
				e.printStackTrace();
			}
			returnClient((ServletResponse) response, transBean);
		}
	}
	/**
	 * 
	 * @param httpResponse
	 * @param transBean
	 */
	private static void returnClient(ServletResponse httpResponse, TransBean transBean) {
		transBean.addResponse("ret_code", transBean.getLocalParam("ret_code"));
		transBean.addResponse("ret_msg", transBean.getLocalParam("ret_msg"));
		String retData = JsonUtil.objectToJson(transBean.getResponse());
		log.info("retrunClient:[{}]", retData);
		OutputStream out = null;
		try {
			out = httpResponse.getOutputStream();
			out.write(retData.getBytes(Global.charset()));
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		} catch (IOException e1) {
			e1.printStackTrace();
		} finally {
			try {
				out.close();
			} catch (IOException e1) {
			}
		}
	}
	/**
	 * 公共初始化参数
	 * 
	 * @param transBean
	 * @throws ErrorException
	 */
	public void initParamSuper(TransBean transBean) throws ErrorException {
		String uuid = TransUtilEasysp.generateShortUuid();
		transBean.addLocalParam("uuid", uuid);
		transBean.addLocalParam("trans_date", CalendarUtil.getNowTime("yyyyMMdd"));
		transBean.addLocalParam("trans_time", CalendarUtil.getNowTime("HHmmss"));
		
		if (StringUtils.isBlank((String)transBean.getLocalParam("temp_user_id"))){
			transBean.addLocalParam("temp_user_id", transBean.getLocalParam("id_value"));
		}
		if(TransUtilEasysp.stringEquals(TransConstEasysp.ENT_USER_TRANS_CODE, transBean.getLocal("trans_code"))){  //企业用户是否已登录
			chkEntUserLogin(transBean);
		}
		initParam(transBean);
	}

	public abstract void initParam(TransBean transBean) throws ErrorException;

	/**
	 * 公共验证参数不为空
	 * 
	 * @param transBean
	 * @throws ErrorException
	 */
	public void dataCheckSuper(TransBean transBean) throws ErrorException {
//		StringUtil.checkNeedDatas(TransConstEasysp.CHANNEL_ID+"|"+TransConstEasysp.TRANS_ID+"|head_osnumber", transBean.getLocalMap());
		StringUtil.checkNeedDatas(TransConstEasysp.TRANS_CODE+"|ip", transBean.getLocalMap());
		dataCheck(transBean);
	}

	/**
	 * 验证参数不为空
	 * @param transBean
	 * @throws ErrorException
	 */
	public abstract void dataCheck(TransBean transBean) throws ErrorException;

	/**
	 * 公共字段长度 格式的校验
	 * 
	 * @param transBean
	 * @throws ErrorException
	 */
	public void validateParamsSuper(TransBean transBean) throws ErrorException {
		validateParams(transBean);
	}

	/**
	 * 字段长度 格式的校验
	 * 
	 * @param transBean
	 * @throws ErrorException
	 */
	public abstract void validateParams(TransBean transBean) throws ErrorException;

	/**
	 * 公共业务逻辑校验
	 * 
	 * @param transBean
	 * @throws ErrorException
	 */
	public  void busiCheckSuper(TransBean transBean) throws ErrorException{
//		verifyLogin(transBean);
		busiCheck(transBean);
	}
	public abstract void verifyLogin(TransBean transBean) throws ErrorException;

	/**
	 * 业务逻辑校验
	 * 
	 * @param transBean
	 * @throws ErrorException
	 */
	public abstract void busiCheck(TransBean transBean) throws ErrorException;

	public abstract void doBusi(TransBean transBean) throws ErrorException, SqlException, Exception;

	/**
	 * 执行请求
	 * 
	 * @param transBean
	 * @throws Exception
	 */
	public final void doMain(TransBean transBean) throws Exception {
		//this.securityCheck(transBean);
		this.initParamSuper(transBean);
		this.dataCheckSuper(transBean);
		this.validateParamsSuper(transBean);	 
		this.busiCheckSuper(transBean);
		this.doBusi(transBean);
		this.statisticsLog(transBean,transBean.getLocal("trans_code"));
		//this.securityOut(transBean);

	}

	public void securityCheck(TransBean transBean)throws ErrorException{

		//手机设备唯一标识
		if(StringUtil.isBlank((String)transBean.getLocalParam("head_osnumber"))){
			throw new ErrorException(ErrorCodeEasysp.ERROR_EASYSP_F992_CODE, ErrorCodeEasysp.ERROR_EASYSP_F992_MSG);
		}
		//########################SECURITY CODE START##########################################################################################################
		
		
		//调取服务获得三种钥匙
		ConsumerBean getMainKeyBean=ConsumerBeanUtil.getConsumerBean(transBean);
		getMainKeyBean.addRequest("head_osnumber",transBean.getLocalParam("head_osnumber"));
		getMainKeyBean.addRequest("flag", TransConstEasysp.KEY_STATUS_FLAG_AGAIN);
		RpcBean baseKeyBean=null;
		try {
			baseKeyBean=this.getMainKeyService.execute(getMainKeyBean);
		} catch (RpcException e) {
			throw new ErrorException(ErrorCodeEasysp.ERROR_EASYSP_F990_CODE,ErrorCodeEasysp.ERROR_EASYSP_F990_MSG);
		}
		TransUtilEasysp.verifyServiceReturn(baseKeyBean);
		//主密钥
		String baseKey=(String) baseKeyBean.getResponse().get("base_key");
		
		ConsumerBean getWorkKeyBean=ConsumerBeanUtil.getConsumerBean(transBean);
		getWorkKeyBean.addRequest("head_osnumber",transBean.getLocalParam("head_osnumber"));
		getWorkKeyBean.addRequest("flag", TransConstEasysp.KEY_STATUS_FLAG_AGAIN);
		RpcBean workKeyBean=null;
		
		try {
			workKeyBean=this.getWorkKeyService.execute(getWorkKeyBean);
		} catch (RpcException e) {
			throw new ErrorException(ErrorCodeEasysp.ERROR_EASYSP_F990_CODE,ErrorCodeEasysp.ERROR_EASYSP_F990_MSG);
		}
		TransUtilEasysp.verifyServiceReturn(workKeyBean);
		//加密密钥
		String encodeKey=(String) workKeyBean.getResponse().get("aes_key");
		//获得签名密钥密文   CREDITMONEY_MAKKEY_osnumber CREDITMONEY_ENCODEKEY_osnumber
		String macKey=(String) workKeyBean.getResponse().get("hmd5_key");
		
		//利用主秘钥和工作秘钥密文获得工作秘钥明文
		try {
			encodeKey=new String(new KKAES(baseKey).decrypt(encodeKey));
			macKey=new String(new KKAES(baseKey).decrypt(macKey));
		} catch (Exception e) {
			e.printStackTrace();
			throw new ErrorException(ErrorCodeEasysp.ERROR_EASYSP_SYSTEMBUSY_CODE, ErrorCodeEasysp.ERROR_EASYSP_SYSTEMBUSY_MSG);
		}
		transBean.addLocalParam("baseKey", baseKey);
		transBean.addLocalParam("encodeKey", encodeKey);
		transBean.addLocalParam("macKey", macKey);
		
		//使用工作秘钥明文 解密报文字段
		APPEncrypt.decodeMap(transBean.getLocalMap(), TransConstEasysp.ENCODE_KEYS, encodeKey);
		
		//使用秘钥明文 验证签名
		if(!APPEncrypt.checkMac(macKey, TransConstEasysp.MAC_KEYS, transBean.getLocalMap(), (String)(transBean.getLocalParam("head_mac")))){
			throw new ErrorException(ErrorCodeEasysp.ERROR_EASYSP_F993_CODE, ErrorCodeEasysp.ERROR_EASYSP_F993_MSG);
		}
	}
	
	private void securityOut(TransBean transBean)throws ErrorException {
		//说明:在理财类型的所有交易中,body里面的字段参与加密和签名
		String baseKey = (String)transBean.getLocalParam("baseKey");
		String macKey = (String)transBean.getLocalParam("macKey");
		String encodeKey = (String)transBean.getLocalParam("encodeKey");
		
		String head_mac= APPEncrypt.getMac(macKey, TransConstEasysp.MAC_KEYS, transBean.getResponse());
		transBean.addResponse("head_mac", head_mac);
		
		APPEncrypt.encodeMap(transBean.getResponse(), TransConstEasysp.ENCODE_KEYS, encodeKey);
	}

	private void statisticsLog(TransBean transBean,String transCode){
		try{
			if(TransUtilEasysp.stringEquals(TransConstEasysp.INDEX_TRANS_CODE, transCode)){//首页访问记录
				insertIndexLog(transBean);
			}else if(TransUtilEasysp.stringEquals(TransConstEasysp.INDEX_TRANS_CODE, transCode)){//购买次数
				insertPayTimesLog(transBean);
			}else if(TransUtilEasysp.stringEquals(TransConstEasysp.MOD_USER_MARK_TRANS_CODE, transCode)){//修改用户标记表
				updUserMarkInfo(transBean,transCode);
			}
		}catch(Exception e){
			log.info("==========================统计模块错误："+e.getMessage());
		}
	}
	private void insertIndexLog(TransBean transBean){//添加首页访问记录
		ConsumerBean consumerBean=ConsumerBeanUtil.getConsumerBean(transBean);
		ConsumerBean consumerBean_user=ConsumerBeanUtil.getConsumerBean(transBean);
		consumerBean.addRequest("osnumber", transBean.getLocal("head_osnumber"));
		if(!transBean.getLocal("head_jsessionid").equals("")){
			consumerBean_user.addRequest("head_jsessionid", transBean.getLocalParam("head_jsessionid"));//用户唯一标识符
			consumerBean_user.addRequest("head_osnumber", transBean.getLocalParam("head_osnumber"));//设备唯一标示符（用来判断是否重复登录）
			RpcBean rpcBean=getCustInfoService.execute(consumerBean_user);
			Map<String,Object> userInfo=(Map<String, Object>) rpcBean.getResponseParam("user_info");
			consumerBean.addRequest("user_id", userInfo.get("user_id"));
			consumerBean.addRequest("area_code", userInfo.get("area_code"));
			consumerBean.addRequest("channel_src", userInfo.get("channel_src"));
			consumerBean.addRequest("age_period", userInfo.get("age_period"));
			
		}
		try {
			addHomeVisitService.execute(consumerBean);		
		} catch (Exception e) {
			log.info("=========================添加首页访问记录失败："+e.getMessage());
		}
	}
	
	private void chkEntUserLogin(TransBean transBean) throws ErrorException{//企业用户是否已登录
		ConsumerBean consumerBean=ConsumerBeanUtil.getConsumerBean(transBean);
		ConsumerBean consumerBean_user=ConsumerBeanUtil.getConsumerBean(transBean);
		//校验企业用户是否登录
		if(!transBean.getLocal("head_jessionid").equals("")){
			consumerBean_user.addRequest("head_jessionid", transBean.getLocalParam("head_jessionid"));//用户唯一标识符
			RpcBean rpcBean=null;
			//查询企业成员用户列表
			try {
				rpcBean=getEntUserInfoService.execute(consumerBean_user);
				TransUtilEasysp.verifyServiceReturn(rpcBean);
			} catch (RpcException e) {
				e.printStackTrace();
				throw new ErrorException(ErrorCodeEasysp.ERROR_EASYSP_F004_CODE,ErrorCodeEasysp.ERROR_EASYSP_F990_MSG);
			}
			Map<String,Object> entUserInfo=(Map<String, Object>) rpcBean.getResponseParam("entUserInfo");
			consumerBean.addRequest("ent_id", entUserInfo.get("ent_id"));
			consumerBean.addRequest("enterprise_user_id", entUserInfo.get("enterprise_user_id"));
			consumerBean.addRequest("user_name", entUserInfo.get("user_name"));
			consumerBean.addRequest("user_id", entUserInfo.get("user_id"));
			
		}
	}
	
	private void insertPayTimesLog(TransBean transBean){//添加购买次数记录
		ConsumerBean consumerBean=ConsumerBeanUtil.getConsumerBean(transBean);
		Map<String,Object> userInfo=(Map<String, Object>) transBean.getLocalParam("user_info");
		consumerBean.addRequest("area_code", userInfo.get("area_code"));
		consumerBean.addRequest("channel_src", userInfo.get("channel_src"));
		consumerBean.addRequest("age_period", userInfo.get("age_period"));
			
		try {
			addPayTimesDayService.execute(consumerBean);		
		} catch (Exception e) {
			log.info("=========================添加购买次数记录失败："+e.getMessage());
		}
	}
	private void updUserMarkInfo(TransBean transBean,String transCode){//修改、新增用户标记表
		ConsumerBean consumerBean=ConsumerBeanUtil.getConsumerBean(transBean);
		Map<String,Object> userInfo=(Map<String, Object>) transBean.getLocalParam("user_info");
		consumerBean.addRequest("area_code", userInfo.get("area_code"));
		consumerBean.addRequest("channel_src", userInfo.get("channel_src"));
		consumerBean.addRequest("age_period", userInfo.get("age_period"));
		consumerBean.addRequest("user_id", transBean.getLocalParam("user_id"));
		if(TransUtilEasysp.stringEquals(TransConstEasysp.REGISTER_TRANS_CODE, transCode)){//注册
			consumerBean.addRequest("flag", "is_register");
		}else if(TransUtilEasysp.stringEquals(TransConstEasysp.BANGDING_TRANS_CODE, transCode)){//绑卡
			consumerBean.addRequest("flag", "is_bandding");
		}else if(TransUtilEasysp.stringEquals(TransConstEasysp.PAY_TRANS_CODE, transCode)){//付费（首次和二次）
			consumerBean.addRequest("flag", "pay");
		}else if(TransUtilEasysp.stringEquals(TransConstEasysp.ZNCK_TRANS_CODE, transCode)){//智能存款购买
			consumerBean.addRequest("flag", "znck");
		}else if(TransUtilEasysp.stringEquals(TransConstEasysp.GJS_TRANS_CODE, transCode)){//贵金属购买
			consumerBean.addRequest("flag", "gjs");
		}else if(TransUtilEasysp.stringEquals(TransConstEasysp.LC_TRANS_CODE, transCode)){//理财购买
			consumerBean.addRequest("flag", "lc");
		}
		try {
			modUserFlagService.execute(consumerBean);		
		} catch (Exception e) {
			log.info("=========================修改用户标记失败："+e.getMessage());
		}
	}
}
